package cn.xerllent.wxtp.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageInfo;

import cn.hutool.core.util.ObjectUtil;
import cn.xerllent.common.exception.BadRequestException;
import cn.xerllent.common.service.impl.BaseServiceImpl;
import cn.xerllent.wxtp.entity.WxCorp;
import cn.xerllent.wxtp.entity.WxDepartment;
import cn.xerllent.wxtp.entity.WxDepartmentUser;
import cn.xerllent.wxtp.entity.WxUser;
import cn.xerllent.wxtp.service.WxDepartmentUserService;
import cn.xerllent.wxtp.service.WxUserService;
import cn.xerllent.wxtp.service.mapper.WxUserMapper;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import cn.xerllent.common.utils.FileUtil;
import cn.xerllent.security.security.vo.JwtUser;

@Slf4j
@Service
//@AllArgsConstructor
//@CacheConfig(cacheNames = "user")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class WxUserServiceImpl extends BaseServiceImpl<WxUserMapper, WxUser>  implements WxUserService {
	
	@Resource
	private WxDepartmentUserService wxDepartmentUserService;

    @Override
    //@Cacheable
    public Map<String, Object> queryAll(WxUser filter,Pageable pageable) {
    	pageHelper(pageable);
        PageInfo<WxUser> page = new PageInfo<>(queryAll(filter));
        Map<String, Object> map = new LinkedHashMap<>(2);
        map.put("list", page.getList());
        map.put("total", page.getTotal());
        return map;
    }

    /**
     * 不含部门搜索用户
     * */
    @Override
    //@Cacheable
    public List<WxUser> queryAll(WxUser filter) {
    	//方法1
    	QueryWrapper<WxUser> querywrapper = new QueryWrapper<>();
    	if(ObjectUtil.isNotEmpty(filter)) {
        	if(ObjectUtil.isNotEmpty(filter.getCorpId())) {
        		querywrapper.eq("corp_id", filter.getCorpId());
        	}
        	if(ObjectUtil.isNotEmpty(filter.getName())) {
        		querywrapper.and(w->
        		w.like("name", filter.getName()).or()
        		.like("telephone", filter.getTelephone()).or()
        		.like("alias", filter.getName())
				);
        	}
        	if(filter.getStatus()!=null) {
        		querywrapper.eq("status", filter.getStatus());
        	}
    	}
    	return baseMapper.selectList(querywrapper);
    }

    @Override
    public void download(List<WxUser> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (WxUser wxUser : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", wxUser.getId());
            map.put("企业id", wxUser.getCorpId());
            map.put("成员id", wxUser.getUserId());
            map.put("成员openid", wxUser.getOpenUserid());
            map.put("成员名称", wxUser.getName());
            map.put("性别", wxUser.getGender());
            map.put("头像", wxUser.getAvatar());
            map.put("头像缩略图", wxUser.getThumbAvatar());
            map.put("电话", wxUser.getTelephone());
            map.put("别名", wxUser.getAlias());
            map.put("地址", wxUser.getAddress());
            map.put("主属部门", wxUser.getMainDepartmentId());
            map.put("账户状态", wxUser.getStatus());
            map.put("创建时间", wxUser.getCreatetime());
            map.put("变动时间", wxUser.getUpdatetime());
            //map.put("原始数据包", wxUser.getWxpackage());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
    
	/**
	 * 清除对应Mapper的二级缓存，采用无害删除空数据模拟清空,因为二级缓存更新机制是本表数据更新即可清空<br>
	 * 提供本方法供联表更新查询的实时更新
	 * */
	@Override
	public void clearCache() {
		baseMapper.deleteById(0);
	}
	
	/**
	 * 自定义jwt:detail规范：username=corpId+"$"+userId,计算而成
	 * 根据corpId及WxUser.userId获取
	 * */
    @Override
	public UserDetails loadUserByUsername(String username) {
    	String[] s= username.split("\\$");
    	String corpId= s[0];
    	String userId= s[1];
    	
		WxUser wxUser = getOne(new LambdaQueryWrapper<WxUser>().eq(WxUser::getCorpId, corpId).eq(WxUser::getUserId, userId));

        if (wxUser == null) {
            throw new BadRequestException("账号不存在");
        }
        if (wxUser.getStatus()<1) {
            throw new BadRequestException("账号未激活");
        }

        return createJwtUser(wxUser);
    }
    
	/**
	 * 根据wxUser生成jwtUser
	 * */
   @Override
	public JwtUser createJwtUser(WxUser wxUser) {
		Collection<SimpleGrantedAuthority> authorities = new HashSet<SimpleGrantedAuthority>();

		return new JwtUser(
				wxUser.getId(),
				wxUser.getCorpId(),
				wxUser.getUserId(),
				//自定义detail规范：username=corpId+"$"+userId,计算而成,不单独赋值
				wxUser.getName(), //name=userId,保留字段，第三方不给实际值userId代替
				wxUser.getAlias(),
				wxUser.getGender(),
				wxUser.getAvatar(),
				wxUser.getMainDepartmentId(),
				null,
				wxUser.getTelephone(),
				authorities,
				wxUser.getStatus()>0,
				null
				);
    }
   
	/**
	 * 同步指定企业部门用户到本地数据库
	 * 使用企业api时，先调用此方法:如果没有企业accesstoken则通过api获取并缓存到storage
	 * wxCpTpService.getCorpToken(corp.getCorpId(), corp.getPermanentCode(),false);
	 * @param wxCpTpService 应用api服务
	 * @param depart 企业部门对象
	 */
	@Override
	public void syncDepartmentUsers(final WxCpTpService wxCpTpService, final WxDepartment depart) {
		try {
			//使用企业api时，先调用此方法:如果没有企业accesstoken则通过api获取并缓存到storage
//			wxCpTpService.getCorpToken(corp.getCorpId(), corp.getPermanentCode(),false);
			
			List<WxCpUser>  users = wxCpTpService.getWxCpTpUserService().listByDepartment(depart.getDepartmentId().longValue(), false, null, depart.getCorpId());
			
			List<WxDepartmentUser> wxDepartmentUsers = new ArrayList<WxDepartmentUser>();
			List<WxUser> wxUsers = users.stream().map(user ->{
				//用户处理
				WxUser u = getOne(new LambdaUpdateWrapper<WxUser>().eq(WxUser::getCorpId, depart.getCorpId()).eq(WxUser::getUserId, user.getUserId()));
				if(u==null) { u = new WxUser(); }
				u.setCorpId(depart.getCorpId());
				if(user.getMainDepartment()!=null) u.setMainDepartmentId(Integer.parseInt(user.getMainDepartment()));
				u.setUserId(user.getUserId());
				u.setOpenUserid(user.getOpenUserId());
				u.setName(user.getName());
				if(user.getAlias()!=null)u.setAlias(user.getAlias());
				u.setAvatar(user.getAvatar());
				if(user.getGender()!=null) u.setGender(user.getGender().getCode());
				u.setStatus(user.getStatus());
				u.setWxpackage(user.toJson());
				
				//部门用户关系处理，只限定本方法的指定的部门id,其他部门多余的不考虑
				for(int i=0;i<user.getDepartIds().length;i++) {
					if(depart.getDepartmentId().longValue() == user.getDepartIds()[i]) {
						WxDepartmentUser du = new WxDepartmentUser();
						du.setCorpId(depart.getCorpId());
						du.setDepartmentId(depart.getDepartmentId());
						du.setUserId(user.getUserId());
						try {du.setIs_leader(user.getIsLeaderInDept()[i]>0);} catch (Exception e) {}
						try {du.setOd(user.getOrders()[i]);} catch (Exception e) {}
						wxDepartmentUsers.add(du);
					}
				}
				
				return u;
				}).collect(Collectors.toList());
			
			saveOrUpdateBatch(wxUsers);
			
			
			//更新部门用户关系数据，指定部门
			//1.删除原部门下的关系
			wxDepartmentUserService.remove(new LambdaUpdateWrapper<WxDepartmentUser>().eq(WxDepartmentUser::getCorpId, depart.getCorpId()).eq(WxDepartmentUser::getDepartmentId, depart.getDepartmentId()));
			//2.保存新关系
			wxDepartmentUserService.saveBatch(wxDepartmentUsers);
			
			
		} catch (WxErrorException e) {
			log.error("syncDepartmentUsers err:", e);
		}
	}
}
